/**
 * 自定义任务弹窗节点
 */
import { assign, forEach, isArray, every } from "min-dash";

import { is } from "bpmn-js/lib/util/ModelUtil";

import { isExpanded, isEventSubProcess } from "bpmn-js/lib/util/DiUtil";

import { isAny } from "bpmn-js/lib/features/modeling/util/ModelingUtil";

// import { getChildLanes } from "bpmn-js/lib/features/modeling/util/LaneUtil";

import { hasPrimaryModifier } from "diagram-js/lib/util/Mouse";

/**
 * A provider for BPMN 2.0 elements context pad
 */
export default function ContextPadProvider(
  config,
  injector,
  eventBus,
  contextPad,
  modeling,
  elementFactory,
  connect,
  create,
  popupMenu,
  canvas,
  rules,
  translate
) {
  config = config || {};

  contextPad.registerProvider(this);

  this._contextPad = contextPad;

  this._modeling = modeling;

  this._elementFactory = elementFactory;
  this._connect = connect;
  this._create = create;
  this._popupMenu = popupMenu;
  this._canvas = canvas;
  this._rules = rules;
  this._translate = translate;

  if (config.autoPlace !== false) {
    this._autoPlace = injector.get("autoPlace", false);
  }

  eventBus.on("create.end", 250, function (event) {
    let context = event.context,
      shape = context.shape;

    if (!hasPrimaryModifier(event) || !contextPad.isOpen(shape)) {
      return;
    }

    let entries = contextPad.getEntries(shape);

    if (entries.replace) {
      entries.replace.action.click(event, shape);
    }
  });
}

ContextPadProvider.$inject = [
  "config.contextPad",
  "injector",
  "eventBus",
  "contextPad",
  "modeling",
  "elementFactory",
  "connect",
  "create",
  "popupMenu",
  "canvas",
  "rules",
  "translate"
];

ContextPadProvider.prototype.getMultiElementContextPadEntries = function (elements) {
  let modeling = this._modeling;

  let actions = {};
  if (this._isDeleteAllowed(elements)) {
    assign(actions, {
      delete: {
        group: "edit",
        className: "bpmn-icon-trash",
        title: this._translate("Remove"),
        action: {
          click: function (event, elements) {
            modeling.removeElements(elements.slice());
          }
        }
      }
    });
  }

  return actions;
};

/**
 * @param {djs.model.Base[]} elements
 * @return {boolean}
 */
ContextPadProvider.prototype._isDeleteAllowed = function (elements) {
  let baseAllowed = this._rules.allowed("elements.delete", {
    elements: elements
  });

  if (isArray(baseAllowed)) {
    return every(baseAllowed, function (element) {
      return includes(baseAllowed, element);
    });
  }

  return baseAllowed;
};

ContextPadProvider.prototype.getContextPadEntries = function (element) {
  //  contextPad = this._contextPad,
  let modeling = this._modeling,
    elementFactory = this._elementFactory,
    // connect = this._connect,
    create = this._create,
    popupMenu = this._popupMenu,
    rules = this._rules,
    autoPlace = this._autoPlace,
    translate = this._translate;

  let actions = {};

  if (element.type === "label") {
    return actions;
  }

  let businessObject = element.businessObject;
  // function startConnect(event, element) {
  //   connect.start(event, element);
  // }

  function removeElement(e, element) {
    modeling.removeElements([element]);
  }

  // function getReplaceMenuPosition(element) {
  //   let Y_OFFSET = 5;

  //   let pad = contextPad.getPad(element).html;

  //   let padRect = pad.getBoundingClientRect();

  //   let pos = {
  //     x: padRect.left,
  //     y: padRect.bottom + Y_OFFSET
  //   };

  //   return pos;
  // }

  /**
   * Create an append action
   *
   * @param {string} type
   * @param {string} className
   * @param {string} [title]
   * @param {Object} [options]
   *
   * @return {Object} descriptor
   */
  function appendAction(type, className, title, options) {
    // if (typeof title !== "string") {
    //   options = title;
    //   title = translate("Append {type}", { type: type.replace(/^bpmn:/, "") });
    // }

    function appendStart(event, element) {
      let shape = elementFactory.createShape(assign({ type: type }, options));
      // if (options) {
      //   shape.businessObject.name = options.name;
      // }
      create.start(event, shape, {
        source: element
      });
    }

    let append = autoPlace
      ? function (event, element) {
          let shape = elementFactory.createShape(assign({ type: type }, options));
          if (options) {
            shape.businessObject.name = options.name;
          }
          autoPlace.append(element, shape);
        }
      : appendStart;

    return {
      group: "model",
      className: className,
      title: title,
      action: {
        dragstart: appendStart,
        click: append
      }
    };
  }

  // function splitLaneHandler(count) {
  //   return function (event, element) {
  //     // actual split
  //     modeling.splitLane(element, count);

  //     // refresh context pad after split to
  //     // get rid of split icons
  //     contextPad.open(element, true);
  //   };
  // }

  if (isAny(businessObject, ["bpmn:Lane", "bpmn:Participant"]) && isExpanded(element)) {
    // let childLanes = getChildLanes(element);
    // assign(actions, {
    //   "lane-insert-above": {
    //     group: "lane-insert-above",
    //     className: "bpmn-icon-lane-insert-above",
    //     title: translate("Add Lane above"),
    //     action: {
    //       click: function (event, element) {
    //         modeling.addLane(element, "top");
    //       }
    //     }
    //   }
    // });
    // if (childLanes.length < 2) {
    //   if (element.height >= 120) {
    //     assign(actions, {
    //       "lane-divide-two": {
    //         group: "lane-divide",
    //         className: "bpmn-icon-lane-divide-two",
    //         title: translate("Divide into two Lanes"),
    //         action: {
    //           click: splitLaneHandler(2)
    //         }
    //       }
    //     });
    //   }
    //   if (element.height >= 180) {
    //     assign(actions, {
    //       "lane-divide-three": {
    //         group: "lane-divide",
    //         className: "bpmn-icon-lane-divide-three",
    //         title: translate("Divide into three Lanes"),
    //         action: {
    //           click: splitLaneHandler(3)
    //         }
    //       }
    //     });
    //   }
    // }
    // assign(actions, {
    //   "lane-insert-below": {
    //     group: "lane-insert-below",
    //     className: "bpmn-icon-lane-insert-below",
    //     title: translate("Add Lane below"),
    //     action: {
    //       click: function (event, element) {
    //         modeling.addLane(element, "bottom");
    //       }
    //     }
    //   }
    // });
  }

  if (is(businessObject, "bpmn:FlowNode")) {
    if (is(businessObject, "bpmn:EventBasedGateway")) {
      // assign(actions, {
      //   "append.receive-task": appendAction("bpmn:ReceiveTask", "bpmn-icon-receive-task", translate("Append ReceiveTask")),
      //   "append.message-intermediate-event": appendAction(
      //     "bpmn:IntermediateCatchEvent",
      //     "bpmn-icon-intermediate-event-catch-message",
      //     translate("Append MessageIntermediateCatchEvent"),
      //     { eventDefinitionType: "bpmn:MessageEventDefinition" }
      //   ),
      //   "append.timer-intermediate-event": appendAction(
      //     "bpmn:IntermediateCatchEvent",
      //     "bpmn-icon-intermediate-event-catch-timer",
      //     translate("Append TimerIntermediateCatchEvent"),
      //     { eventDefinitionType: "bpmn:TimerEventDefinition" }
      //   ),
      //   "append.condition-intermediate-event": appendAction(
      //     "bpmn:IntermediateCatchEvent",
      //     "bpmn-icon-intermediate-event-catch-condition",
      //     translate("Append ConditionIntermediateCatchEvent"),
      //     { eventDefinitionType: "bpmn:ConditionalEventDefinition" }
      //   ),
      //   "append.signal-intermediate-event": appendAction(
      //     "bpmn:IntermediateCatchEvent",
      //     "bpmn-icon-intermediate-event-catch-signal",
      //     translate("Append SignalIntermediateCatchEvent"),
      //     { eventDefinitionType: "bpmn:SignalEventDefinition" }
      //   )
      // });
    } else if (isEventType(businessObject, "bpmn:BoundaryEvent", "bpmn:CompensateEventDefinition")) {
      // assign(actions, {
      //   "append.compensation-activity": appendAction("bpmn:Task", "bpmn-icon-task", translate("Append compensation activity"), {
      //     isForCompensation: true
      //   })
      // });
    } else if (
      !is(businessObject, "bpmn:EndEvent") &&
      !businessObject.isForCompensation &&
      !isEventType(businessObject, "bpmn:IntermediateThrowEvent", "bpmn:LinkEventDefinition") &&
      !isEventSubProcess(businessObject)
    ) {
      assign(actions, {
        "append.end-event": appendAction("bpmn:EndEvent", "bpmn-icon-end-event-none", translate("Append EndEvent"), {
          name: "结束"
        }),
        // "append.gateway": appendAction("bpmn:ExclusiveGateway", "bpmn-icon-gateway-none", translate("Append Gateway")),
        "append.append-user-task": appendAction("bpmn:UserTask", "bpmn-icon-user-task", "添加用户任务", {
          name: "审批人"
        })
        // "append.intermediate-event": appendAction(
        //   "bpmn:IntermediateThrowEvent",
        //   "bpmn-icon-intermediate-event-none",
        //   translate("Append Intermediate/Boundary Event")
        // )
      });
    }
  }

  if (!popupMenu.isEmpty(element, "bpmn-replace") && !is(businessObject, "bpmn:SequenceFlow")) {
    // Replace menu entry
    // assign(actions, {
    //   replace: {
    //     group: "edit",
    //     className: "bpmn-icon-screw-wrench",
    //     title: translate("Change type"),
    //     action: {
    //       click: function (event, element) {
    //         console.log(element);
    //         let position = assign(getReplaceMenuPosition(element), {
    //           cursor: { x: event.x, y: event.y }
    //         });
    //         popupMenu.open(element, "bpmn-replace", position, {
    //           title: translate("Change element"),
    //           width: 300,
    //           search: true
    //         });
    //       }
    //     }
    //   }
    // });
  }

  // if (is(businessObject, "bpmn:SequenceFlow")) {
  //   assign(actions, {
  //     "append.text-annotation": appendAction("bpmn:TextAnnotation", "bpmn-icon-text-annotation")
  //   });
  // }

  if (isAny(businessObject, ["bpmn:FlowNode", "bpmn:InteractionNode", "bpmn:DataObjectReference", "bpmn:DataStoreReference"])) {
    // assign(actions, {
    //   "append.text-annotation": appendAction("bpmn:TextAnnotation", "bpmn-icon-text-annotation"),
    //   connect: {
    //     group: "connect",
    //     className: "bpmn-icon-connection-multi",
    //     title: translate("Connect using " + (businessObject.isForCompensation ? "" : "Sequence/MessageFlow or ") + "Association"),
    //     action: {
    //       click: startConnect,
    //       dragstart: startConnect
    //     }
    //   }
    // });
  }

  if (is(businessObject, "bpmn:TextAnnotation")) {
    // assign(actions, {
    //   connect: {
    //     group: "connect",
    //     className: "bpmn-icon-connection-multi",
    //     title: translate("Connect using Association"),
    //     action: {
    //       click: startConnect,
    //       dragstart: startConnect
    //     }
    //   }
    // });
  }

  if (isAny(businessObject, ["bpmn:DataObjectReference", "bpmn:DataStoreReference"])) {
    // assign(actions, {
    //   connect: {
    //     group: "connect",
    //     className: "bpmn-icon-connection-multi",
    //     title: translate("Connect using DataInputAssociation"),
    //     action: {
    //       click: startConnect,
    //       dragstart: startConnect
    //     }
    //   }
    // });
  }

  // if (is(businessObject, "bpmn:Group")) {
  //   assign(actions, {
  //     "append.text-annotation": appendAction("bpmn:TextAnnotation", "bpmn-icon-text-annotation")
  //   });
  // }
  // delete element entry, only show if allowed by rules
  let deleteAllowed = rules.allowed("elements.delete", { elements: [element] });
  if (element.type === "bpmn:StartEvent" || element.type === "bpmn:SequenceFlow") {
    deleteAllowed = false;
  }
  if (isArray(deleteAllowed)) {
    // was the element returned as a deletion candidate?
    deleteAllowed = deleteAllowed[0] === element;
  }

  if (deleteAllowed) {
    assign(actions, {
      delete: {
        group: "edit",
        className: "bpmn-icon-trash",
        title: translate("Remove"),
        action: {
          click: removeElement
        }
      }
    });
  }

  return actions;
};

// helpers /////////

function isEventType(eventBo, type, definition) {
  let isType = eventBo.$instanceOf(type);
  let isDefinition = false;

  let definitions = eventBo.eventDefinitions || [];
  forEach(definitions, function (def) {
    if (def.$type === definition) {
      isDefinition = true;
    }
  });

  return isType && isDefinition;
}

function includes(array, item) {
  return array.indexOf(item) !== -1;
}
